package com.wengzw.message.common.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.util.concurrent.Callable;

/**
 * @author wengzw
 * @date 2022/6/17 16:22
 */
@Slf4j
public class DownloadThread implements Callable<Boolean> {

    /**
     * 每次读取的数据块大小 每次100M
     */
    private static int BYTE_SIZE = 1024 * 100;
    /**
     * 下载链接
     */
    private String url;
    /**
     * 下载开始位置
     */
    private Long startPos;
    /**
     * 要下载的文件区块大小
     */
    private Long endPos;
    /**
     * 标识多线程下载的第几部分
     */
    private Integer part;
    /**
     * 文件总大小
     */
    private Long contentLength;

    public DownloadThread(String url, long startPos, Long endPos, Integer part, Long contentLength) {
        this.url = url;
        this.startPos = startPos;
        this.endPos = endPos;
        this.part = part;
        this.contentLength = contentLength;
    }

    @Override
    public Boolean call() throws Exception {
        // 临时文件后缀
        String FILE_TEMP_SUFFIX = ".temp";
        if (url == null || url.trim() == "") {
            throw new RuntimeException("下载路径不正确");
        }
        // 获取文件名
        String httpFileName = HttpUtls.getHttpFileName(url);
        if (part != null) {
            httpFileName = httpFileName + FILE_TEMP_SUFFIX + part;
        }

        // 本地文件大小
        Long localFileContentLength = FileUtils.getFileContentLength(httpFileName);
        LogThread.LOCAL_FINISH_SIZE.addAndGet(localFileContentLength);
        if (localFileContentLength >= endPos - startPos) {
            log.info("{} 已经下载完毕，无需重复下载", httpFileName);
            LogThread.DOWNLOAD_FINISH_THREAD.addAndGet(1);
            return true;
        }
        if (endPos.equals(contentLength)) {
            endPos = null;
        }

        HttpURLConnection httpUrlConnection = HttpUtls.getHttpUrlConnection(url, startPos + localFileContentLength, endPos);
        //从java1.7版本开始,支持使用try后面跟随（）括号管理释放资源,
        // 前提是这些可关闭的资源必须实现 java.lang.AutoCloseable 接口。
        try (InputStream input = httpUrlConnection.getInputStream();
             BufferedInputStream bis = new BufferedInputStream(input);
             RandomAccessFile rw = new RandomAccessFile(httpFileName, "rw");) {
            rw.seek(localFileContentLength);
            byte[] bytes = new byte[BYTE_SIZE];
            int len = -1;
            while ((len = bis.read(bytes)) != -1) {
                rw.write(bytes, 0, len);
                LogThread.DOWNLOAD_SIZE.addAndGet(len);
            }
        } catch (FileNotFoundException e) {
            log.info("ERROR 要下载的文件路径不存在 {}" ,url);
            return false;
        } catch (Exception e) {
            log.info("下载出现异常");
            e.printStackTrace();
            return false;
        } finally {
            httpUrlConnection.disconnect();
            LogThread.DOWNLOAD_FINISH_THREAD.addAndGet(1);
        }
        return true;
    }
}
